package com.fdl.common.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * @description excel操作
 * @project: cp-website
 * @Date:2011-1-7
 * @version 1.0
 * @Company: 33e9
 * @author junWu.zhu
 */
public class ExcelOperate<T> {

	// Log
	private static Log log = LogFactory.getLog(ExcelOperate.class);
	// 文件名
	private String fileName;
	// 表头名集合
	private String[] thNames;
	// 属性名集合
	private String[] fields;
	// 数据集合
	private List<T> dataList;
	// excel sheet名称 : 默认名称sheet1
	private String sheetName = "sheet1";
	// HSSFWork
	private HSSFWorkbook hssfWorkbook;
	// Sheet
	private HSSFSheet hssfSheet;
	// Map : 数据存储方式 Map<属性名,表头名>
	private Map<String, String> thAndFieldMap;
	// InputStream : 导出文件流
	private InputStream inputStream;
	// 文件
	private File file;
	// 泛型类
	private T t;

	public ExcelOperate() {
		super();
	}

	/**
	 * @param fileName
	 *            :文件名
	 * @param dataList
	 *            : 数据集合
	 * @param sheetName
	 *            : excel sheet 名
	 * @param thAndFieldMap
	 *            : 表头和属性名Map 存储方式 Map<属性名,表头名>
	 */
	public ExcelOperate(List<T> dataList, String sheetName, String fileName,
			Map<String, String> thAndFieldMap) {
		super();
		this.dataList = dataList;
		this.fileName = fileName;
		this.sheetName = sheetName;
		this.thAndFieldMap = thAndFieldMap;
	}

	/**
	 * 
	 * @param dataList
	 *            : 数据集合
	 * @param fields
	 *            : 属性名集合
	 * @param fileName
	 *            :文件名
	 * @param sheetName
	 *            : excel sheet 名
	 * @param thNames
	 *            : 表头名
	 */
	public ExcelOperate(List<T> dataList, String[] fields, String fileName,
			String sheetName, String[] thNames) {
		super();
		this.dataList = dataList;
		this.fields = fields;
		this.fileName = fileName;
		this.sheetName = sheetName;
		this.thNames = thNames;
	}

	/**
	 * excel导出文件流 ExcelOperate设置(thNames, fields, dataList, sheetName)
	 * 
	 * @return
	 */
	public InputStream excelExport(final String fileName,
			Map<String, String> thAndFieldMap, List<T> dataList,
			final String sheetName) {
		this.dataList = dataList;
		this.fileName = fileName;
		this.sheetName = sheetName;
		this.thAndFieldMap = thAndFieldMap;
		this.fields = thAndFieldMap.keySet().toArray(new String[] {});
		this.thNames = thAndFieldMap.values().toArray(new String[] {});
		return excelExport(thNames, fields, dataList, sheetName);
	}

	/**
	 * excel导出文件流 ExcelOperate设置(thNames, fields, dataList, sheetName)
	 * 
	 * @return
	 */
	public InputStream excelExportAfterBatchAdd() {
		return excelExport(thNames, fields, dataList, sheetName);
	}

	/**
	 * excel导出文件流
	 * 
	 * @param filename
	 *            文件名
	 * @param columns
	 *            表头名
	 * @param fields
	 *            属性
	 * @param list
	 *            数据
	 * @param sheet
	 * @return
	 */
	public InputStream excelExport(final String fileName,
			final String[] thNames, final String[] fields, List<T> dataList,
			final String sheetName) {
		this.fileName = fileName;
		return excelExport(thNames, fields, dataList, sheetName);
	}

	/**
	 * excel导出文件流 : 批量导出
	 * 
	 * @param filename
	 *            文件名
	 * @param columns
	 *            表头名
	 * @param fields
	 *            属性
	 * @param list
	 *            数据
	 * @param sheet
	 * @return
	 */
	public InputStream excelExport() {
		batchAdd(thNames, fields, dataList, sheetName);
		return excelExport(thNames, fields, dataList, sheetName);
	}

	/**
	 * 直接导出 : 不需要经过batchAdd方法 excel导出文件流
	 * 
	 * @param columns
	 *            表头名
	 * @param fields
	 *            属性
	 * @param list
	 *            数据
	 * @param sheet
	 * @return
	 */
	public InputStream excelExport(final String[] thNames,
			final String[] fields, List<T> dataList, String sheetName) {
		this.thNames = thNames;
		this.fields = fields;
		this.dataList = dataList;
		this.sheetName = sheetName;
		// 构建文件流
		try {
			file = new File(fileName + ConditionCollection.FILE_EXCEL_SUFFIX);
			hssfWorkbook.write(new FileOutputStream(file));
			inputStream = new FileInputStream(file);
		} catch (Exception e) {
			log.error("excelExport function:" + e.getMessage());
		}
		return inputStream;
	}

	/**
	 * <p>
	 * 批量添加数据
	 * </p>
	 * 对象设置 thNames, fields, dataList, sheetName
	 */
	public void batchAdd() {
		batchAdd(thNames, fields, dataList, sheetName);
	}

	/**
	 * 批量添加数据
	 * 
	 * @param columns
	 *            表头名
	 * @param fields
	 *            属性
	 * @param list
	 *            数据
	 * @param sheet
	 * @return
	 */
	public void batchAdd(final String[] thNames, final String[] fields,
			List<T> dataList, String sheetName) {
		hssfWorkbook = new HSSFWorkbook();// 创建一个工作间
		hssfSheet = hssfWorkbook.createSheet(sheetName);// 创建一个sheet
		// 创建第一行(存储表头名)
		HSSFRow row = hssfSheet.createRow(0);// 创建第一行
		// 表头
		HSSFCell cell = null;
		for (int cellIndex = 0; cellIndex < thNames.length; cellIndex++) {
			cell = row.createCell(cellIndex);
			cell.setCellValue(thNames[cellIndex]); // 设置表头名
		}

		if (null != dataList && dataList.size() > 0) {
			// 数据拆分 : 创建行
			for (int rowIndex = 0; rowIndex < dataList.size(); rowIndex++) {
				// 创建属性对象(创建+1行)
				row = hssfSheet.createRow(rowIndex + 1);
				for (int f = 0; f < fields.length; f++) {
					// 创建列
					T t = dataList.get(rowIndex);
					Object rtnV = getFieldRtnVal(t, ConditionCollection.PREFIX_GET,fields[f]
							);
					cell = row.createCell(f);
					// 设置cell数据
					setCellValue(cell, rtnV);
				}
			}
		}
	}

	/**
	 * 添加单行
	 * 
	 * @param thNames
	 *            : 表头名数组
	 * @param values
	 *            : 值数组
	 */
	public void addTr(final String[] thNames, Object... values) {
		if (hssfWorkbook == null && hssfSheet == null) {
			hssfWorkbook = new HSSFWorkbook();
			hssfSheet = hssfWorkbook.createSheet(sheetName);
		}
		int rowNum = hssfSheet.getLastRowNum() + 1;
		HSSFRow row = null;
		HSSFCell cell = null;
		row = hssfSheet.createRow(rowNum);
		for (int i = 0; i < thNames.length; i++) {
			cell = row.createCell(i);
			setCellValue(cell, thNames[i]);
		}
		row = hssfSheet.createRow(rowNum + 1);
		for (int i = 0; i < thNames.length; i++) {
			cell = row.createCell(i);
			setCellValue(cell, values[i]);
		}
	}

	/**
	 * 由于HSSFCell.setCellValue不可设置object,必须转换为常用数据类型
	 * 
	 * @param cell
	 * @param cellValue
	 */
	protected void setCellValue(HSSFCell cell, Object cellValue) {
		if (cellValue instanceof Number) {
			cell.setCellValue(cellValue.toString());
		} else if (cellValue instanceof Boolean) {
			cell.setCellValue((Boolean) cellValue);
		} else if (cellValue instanceof Date) {
			cell.setCellValue(new SimpleDateFormat(
					ConditionCollection.FORMATTER_DATETIME).format(cellValue));
		} else {
			cell.setCellValue((String) cellValue);
		}
	}

	/**
	 * 返回对象中单个属性值 : 针对 get无参方法 如果传递属性为Map..传递规则 : map.key
	 * 
	 * @param obj
	 *            对象
	 * @param field
	 *            属性
	 */
	@SuppressWarnings("unchecked")
	public static Object getFieldRtnVal(Object obj, String prefix,
			String field, Object... params) {
		StringBuffer method = new StringBuffer();
		method.append(prefix);
		// 属性名区分
		String f = "", mapKey = "";
		// 如果属性为map,则map表现形式:"map.key"
		if (field.indexOf(ConditionCollection.STR_POINT) != -1) {
			f = field.split(ConditionCollection.SPLIT_POINT)[0];
			// 取map.key
			mapKey = field.split(ConditionCollection.SPLIT_POINT)[1];
		} else {
			// 非Map属性
			f = field;
		}
		method.append(f.substring(0, 1).toUpperCase());
		method.append(f.substring(1));
		// 返回对象
		Object rtnObj = null;
		try {
			
			// 取参数类
			ArrayList<Class> classArr = new ArrayList<Class>();
			for(Object parmObj : params){
				classArr.add(parmObj.getClass());
			}
			// 如果使用getDeclaredMethod，只可使用该类本身声明的方法 (父类方法不包括在内)
			Method newMethod = obj.getClass().getMethod(method.toString(),
					classArr.toArray(new Class[]{}));
			
			classArr = null;
			rtnObj = newMethod.invoke(obj, params);
			// 返回对象 : Map
			if (rtnObj instanceof Map) {
				// 返回值为map.get(key)
				rtnObj = ((Map) rtnObj).get(mapKey);
				mapKey = null;
				f = null;
			}

			method = null;
			newMethod = null;

		} catch (Exception e) {
			log.error(">>>>>>>>> getMethodRtnVal(Object obj, String field):\n"
					+ e.getMessage());
			e.printStackTrace();
		}
		return rtnObj;
	}

	/**
	 * 文件名称(转为ISO-8859-1编码格式后):主要是提供给下载
	 * 
	 * @return
	 */
	public String getFileName() {
		try {
			return new String(fileName.getBytes(),
					ConditionCollection.ENCODING_ISO_8859_1);
		} catch (UnsupportedEncodingException e) {
			return fileName;
		}
	}

	/**
	 * 原始文件名称
	 * 
	 * @return
	 */
	public String getDefaultFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public String[] getThNames() {
		return thNames;
	}

	public void setThNames(String[] thNames) {
		this.thNames = thNames;
	}

	public String[] getFields() {
		return fields;
	}

	public void setFields(String[] fields) {
		this.fields = fields;
	}

	public List<T> getDataList() {
		return dataList;
	}

	public void setDataList(List<T> dataList) {
		this.dataList = dataList;
	}

	public String getSheetName() {
		return sheetName;
	}

	public void setSheetName(String sheetName) {
		this.sheetName = sheetName;
	}

	public HSSFWorkbook getHssfWorkbook() {
		return hssfWorkbook;
	}

	public void setHssfWorkbook(HSSFWorkbook hssfWorkbook) {
		this.hssfWorkbook = hssfWorkbook;
	}

	public HSSFSheet getHssfSheet() {
		return hssfSheet;
	}

	public void setHssfSheet(HSSFSheet hssfSheet) {
		this.hssfSheet = hssfSheet;
	}

	public Map<String, String> getThAndFieldMap() {
		return thAndFieldMap;
	}

	public void setThAndFieldMap(Map<String, String> thAndFieldMap) {
		fields = thAndFieldMap.keySet().toArray(new String[] {});
		thNames = thAndFieldMap.values().toArray(new String[] {});
		this.thAndFieldMap = thAndFieldMap;
	}

	public InputStream getInputStream() {
		return inputStream;
	}

	public File getFile() {
		return file;
	}

	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}

}
